package heap

import (
	"lesson01/classfile"
	"strconv"
)

type Constant interface{}

type ConstantPool struct {
	class    *Class
	constant []Constant
}

func newConstantPool(e *Class, cfCp classfile.ConstantPool) *ConstantPool {
	cpCount := len(cfCp)
	constants := make([]Constant, cpCount)
	rtCp := &ConstantPool{e, constants}
	for i := 0; i < cpCount; i++ {
		constantInfo := cfCp[i]
		switch constantInfo.(type) {
		case *classfile.ConstantIntegerInfo:
			infoInfo := constantInfo.(*classfile.ConstantIntegerInfo)
			constants[i] = infoInfo.Value()
		case *classfile.ConstantFloatInfo:
			infoInfo := constantInfo.(*classfile.ConstantFloatInfo)
			constants[i] = infoInfo.Value()
		case *classfile.ConstantLongInfo:
			infoInfo := constantInfo.(*classfile.ConstantLongInfo)
			constants[i] = infoInfo.Value()
			i++
		case *classfile.ConstantDoubleInfo:
			infoInfo := constantInfo.(*classfile.ConstantDoubleInfo)
			constants[i] = infoInfo.Value()
			i++
		case *classfile.ConstantStringInfo:
			infoInfo := constantInfo.(*classfile.ConstantStringInfo)
			constants[i] = infoInfo.String()
		case *classfile.ConstantClassInfo:
			infoInfo := constantInfo.(*classfile.ConstantClassInfo)
			constants[i] = newClassRef(rtCp, infoInfo)
		case *classfile.ConstantFieldrefInfo:
			info := constantInfo.(*classfile.ConstantFieldrefInfo)
			constants[i] = newFieldRef(rtCp, info)
		case *classfile.ConstantMethodrefInfo:
			info := constantInfo.(*classfile.ConstantMethodrefInfo)
			constants[i] = newMethodRef(rtCp, info)
		case *classfile.ConstantInterfaceMethodrefInfo:
			methodRefInfo := constantInfo.(*classfile.ConstantInterfaceMethodrefInfo)
			constants[i] = newInterfaceMethodRef(rtCp, methodRefInfo)
		default:
			//todo
		}

	}

	return rtCp
}

func (e *ConstantPool) GetConstant(index uint) Constant {
	if c := e.constant[index]; c != nil {
		return c
	}
	panic("Not found constant " + strconv.Itoa(int(index)))
}
